NCNN ResNet-50 部署

说在前面

因为NCNN的部署是不依赖任何第三方库的,所以在模型部署的过程中,只需要了解CMake编译工程的步骤。具体详见CMake 入门实践

下载ResNet-50模型

caffe model zoo中有对应的各种不同版本的训练好的model,因为是部署,所以我们需要的仅仅是对应的caffemodel文件和deploy.prototxt文件。

转换ncnn网络和模型

  • 首先建立resnet源文件目录
1
2
3
4
5
6

$ cd <ncnn-root-dir>
$ cd examples
$ mkdir resnet
$ cd resnet
$ mkdir model

将下载好的ResNet-50源文件复制到model文件夹中如下所示:

1
2
$ root@a488d431ffee:/home/dl/ncnn/examples/resnet/model# ls
ResNet-50-deploy.prototxt ResNet-50-model.caffemodel

  • caffe 自带了工具可以把老版本的 caffe 网络和模型转换为新版(ncnn的工具只认识新版)
1
2
upgrade_net_proto_text ResNet-50-deploy.prototxt  ncnn-ResNet-50-deploy.prototxt
upgrade_net_proto_binary ResNet-50-model.caffemodel ncnn-ResNet-50-model.caffemodel
  • 输入层改用 Input,因为每次只需要做一个图片,所以第一个 dim 设为 1
1
2
3
4
5
6
7
8
9
10
11
12
13
layer {
name: "input"
type: "Input"
top: "data"
input_param {
shape {
dim: 1
dim: 3
dim: 224
dim: 224
}
}
}
  • 使用 caffe2ncnn 工具转换为 ncnn 的网络描述和模型

注意caffe2ncnn工具在

1
2
3
$ cd <ncnn-root-dir>
$ cd build/tools/caffe/
$ caffe2ncnn ../../../examples/resnet/model/ncnn-ResNet-50-deploy.prototxt ../../../examples/resnet/model/ncnn-ResNet-50-model.caffemodel ../../../examples/resnet/model/resnet-50.param ../../../examples/resnet/model/resnet-50.bin

准备工作全部完成如下,我们最终需要的是resnet-50.binresnet-50.param两个文件:

1
2
root@a488d431ffee:/home/dl/ncnn/examples/resnet/model# ls
ResNet-50-deploy.prototxt ResNet-50-model.caffemodel ncnn-ResNet-50-deploy.prototxt ncnn-ResNet-50-model.caffemodel resnet-50.bin resnet-50.param

建立ResNet工程

  • 需要修改对应的CMakeLists.txt

    • 首先修改examples文件夹下的CMakeLists.txt文件

      1
      2
      # 最后一行添加
      add_subdirectory(resnet)
    • 然后进入resnet文件夹,创建CMakeLists.txt文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      find_package(OpenCV REQUIRED core highgui )

      include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../src)
      include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../src)



      include_directories(${CMAKE_CURRENT_BINARY_DIR})

      add_executable(resnet-50 resnet_50.cpp)
      target_link_libraries(resnet-50 ncnn ${OpenCV_LIBS})
  • 编写resnet_50.cpp(仿照SqueezeNet)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <string>
using namespace std;
using namespace cv;
#include "net.h"

static int detect_resnet(const cv::Mat& bgr, std::vector<float>& cls_scores)
{
ncnn::Net resnet;
resnet.load_param("resnet-50.param");
resnet.load_model("resnet-50.bin");

ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, 224, 224);

const float mean_vals[3] = {104.f, 117.f, 123.f};
in.substract_mean_normalize(mean_vals, 0);

ncnn::Extractor ex = resnet.create_extractor();
ex.set_light_mode(true);

ex.input("data", in);

ncnn::Mat out;
ex.extract("prob", out);

cls_scores.resize(out.c);
for (int j=0; j<out.c; j++)
{
const float* prob = out.data + out.cstep * j;
cls_scores[j] = prob[0];
}

return 0;
}

static int print_topk(const std::vector<float>& cls_scores, int topk, vector<int>& index_result, vector<float>& score_result)
{
// partial sort topk with index
int size = cls_scores.size();
std::vector< std::pair<float, int> > vec;
vec.resize(size);
for (int i=0; i<size; i++)
{
vec[i] = std::make_pair(cls_scores[i], i);
}

std::partial_sort(vec.begin(), vec.begin() + topk, vec.end(), std::greater< std::pair<float, int> >());

// print topk and score
for (int i=0; i<topk; i++)
{
float score = vec[i].first;
int index = vec[i].second;
index_result.push_back(index);
score_result.push_back(score);

//fprintf(stderr, "%d = %f\n", index, score);
}

return 0;
}

static int load_labels(string path, vector<string>& labels)
{
FILE* fp = fopen(path.c_str(), "r");

while (!feof(fp))
{
char str[1024];
fgets(str, 1024, fp);
string str_s(str);

if (str_s.length() > 0)
{
for (int i = 0; i < str_s.length(); i++)
{
if (str_s[i] == ' ')
{
string strr = str_s.substr(i, str_s.length() - i - 1);
labels.push_back(strr);
i = str_s.length();
}
}
}
}
return 0;
}

int main(int argc, char** argv)
{
const char* imagepath = argv[1];
vector<string> labels;
load_labels("synset_words.txt", labels);
cv::Mat m = cv::imread(imagepath, CV_LOAD_IMAGE_COLOR);
if (m.empty())
{
fprintf(stderr, "cv::imread %s failed\n", imagepath);
return -1;
}

std::vector<float> cls_scores;
detect_resnet(m, cls_scores);

vector<int> index;
vector<float> score;
print_topk(cls_scores, 3, index, score);


for (int i = 0; i < index.size(); i++)
{
cout << labels[index[i]] << endl;
}

return 0;
}

运行程序

1
2
3
4
5
6
7
8
$ cd <ncnn-root-dir>
$ cd build
$ cmake ..
$ make
$ cd resnet
$ cp ../../../examples/resnet/model/resnet-50.param ./
$ cp ../../../examples/resnet/model/resnet-50.bin ./
$ ./resnet-50 cat.jpg

结果如下:

1
2
3
Pembroke, Pembroke Welsh corgi
Egyptian cat
red fox, Vulpes vulpes

参考

CMake 入门实践
caffe model zoo
ncnn 组件使用指北 alexnet
Ubuntu16.04—腾讯NCNN框架入门到应用

-------------本文结束 感谢您的阅读-------------
0%